import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DataSource, Repository } from 'typeorm';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User } from './entities/user.entity';

const setTargetFromDto = (target, dto) => {
  Object.entries(dto).forEach(([k, v]) => {
    target[k] = v;
  });
};

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User) private userRepo: Repository<User>,
    private readonly dataSource: DataSource,
  ) {}

  async create(createUserDto: CreateUserDto): Promise<User> {
    const u = this.userRepo.create(new User());
    setTargetFromDto(u, createUserDto);
    u.createdAt = new Date();
    u.editedAt = new Date();

    return await this.userRepo.save(u);
  }

  findAll() {
    return this.userRepo.find();
  }

  findOne(id: number) {
    return this.userRepo.findOne({
      where: { id },
    });
  }

  findUserEmail(email: string) {
    return this.userRepo.findOne({
      where: { email },
    });
  }

  update(id: number, updateUserDto: UpdateUserDto) {
    return this.userRepo.update(
      { id },
      {
        ...updateUserDto,
        editedAt: new Date(),
      },
    );
  }

  async remove(id: number) {
    const u = await this.findOne(id);
    const res = await this.userRepo.delete({ id });
    if (res.affected) {
      return u;
    }
  }

  async createMany(users: CreateUserDto[]) {
    // 事务
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      const us = [];
      users.forEach((createDto) => {
        const u = this.userRepo.create(new User());
        setTargetFromDto(u, createDto);
        us.push(u);
      });
      // NOTICE: map会丢失东西
      // const us = users.map(
      //   ({ name, description, filename, views, isPublished }) => {
      //     const u = this.userRepo.create(new User());
      //     u.name = name;
      //     u.description = description;
      //     u.filename = filename;
      //     u.views = views;
      //     u.isPublished = isPublished;
      //     console.log(u);
      //     return u;
      //   },
      // );

      // 串行执行
      let promise = Promise.resolve();
      let i = 0;
      while (i < us.length) {
        const u = us[i];
        promise = promise.then(() => queryRunner.manager.save(u));
        i++;
      }
      await promise;
      await queryRunner.commitTransaction();
      return us;
    } catch (error) {
      console.log(error);
      await queryRunner.rollbackTransaction();
      throw error;
    } finally {
      await queryRunner.release();
    }
  }
}
